/*
 * 描          述:  <描述>
 * 修  改   人:
 * 修改时间:
 * <修改描述:>
 */
package com.tx.component.basicdata.facade.registry;

import com.tx.component.basicdata.annotation.BasicDataEntity;
import com.tx.component.basicdata.model.BasicData;
import com.tx.component.basicdata.model.BasicDataEntityInfo;
import com.tx.component.basicdata.model.BasicDataViewTypeEnum;
import com.tx.component.basicdata.service.BasicDataService;
import com.tx.core.exceptions.util.AssertUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * BasicDataType的业务层
 * <功能详细描述>
 *
 * @author
 * @version [版本号, ]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class BasicDataEntityRegistry {

    @SuppressWarnings("unused")
    private Logger logger = LoggerFactory
            .getLogger(BasicDataEntityRegistry.class);

    /** 编码到类型的映射 */
    private final Map<String, Class<? extends BasicData>> entityClassMap = new HashMap<>();

    /** 编码到类型的映射 */
    private final Map<String, String> moduleMap = new HashMap<>();

    /** 类型到类型的映射 */
    private final Map<String, BasicDataEntityInfo> entityInfoMap = new HashMap<>();

    /** 类型到类型的映射 */
    private final Map<String, BasicDataService<? extends BasicData>> serviceMap = new HashMap<>();

    /** 编码到类型的映射 */
    private final Map<Class<? extends BasicData>, String> class2typeMap = new HashMap<>();

    /** 编码到类型的映射 */
    private final Map<Class<? extends BasicData>, String> class2moduleMap = new HashMap<>();

    /** 类型到类型的映射 */
    private final Map<Class<? extends BasicData>, BasicDataEntityInfo> class2entityInfoMap = new HashMap<>();

    /** 类型到类型的映射 */
    private final Map<Class<? extends BasicData>, BasicDataService<? extends BasicData>> class2serviceMap =
            new HashMap<>();

    /** <默认构造函数> */
    public BasicDataEntityRegistry() {
        super();
    }

    /**
     * 注册基础数据<br/>
     *
     * @param module
     * @param service
     */
    @SuppressWarnings("unlikely-arg-type")
    public void register(String module,
                         BasicDataService<? extends BasicData> service) {
        AssertUtils.notNull(service, "service is null.");

        /** 获取RawType(泛型类型) */
        Class<? extends BasicData> rawType = service.getRawType();
        AssertUtils.isTrue(BasicData.class.isAssignableFrom(rawType),
                "rawType:{} is not assignableFrom BasicData.",
                new Object[]{rawType});

        //尝试实例化，确认rawType能够被实例化
        BeanUtils.instantiateClass(rawType, BasicData.class);

        //如果是注入的本地业务层;则直接
        String type = service.type();
        String tableName = service.tableName();

        BasicDataEntityInfo info = new BasicDataEntityInfo();
        info.setModule(module);
        info.setEntityClass(rawType);
        info.setTableName(tableName);
        info.setType(type);
        if (rawType.isAnnotationPresent(BasicDataEntity.class)) {
            BasicDataEntity anno = rawType.getAnnotation(BasicDataEntity.class);
            info.setName(
                    StringUtils.isEmpty(anno.name()) ? rawType.getSimpleName()
                            : anno.name());
            info.setRemark(anno.remark());
            info.setViewType(anno.viewType() == null
                    ? BasicDataViewTypeEnum.COMMON_PAGEDLIST
                    : anno.viewType());
            info.setCatalog(anno.catalog());
        } else {
            info.setName(rawType.getSimpleName());
            info.setRemark("");
            info.setViewType(BasicDataViewTypeEnum.COMMON_PAGEDLIST);
            info.setCatalog("");
        }

        AssertUtils.isTrue(!entityClassMap.containsKey(rawType),
                "rawType:{} : service :{} is exist.",
                new Object[]{rawType, service});

        //注册写入<br/>
        this.entityClassMap.put(type, rawType);
        this.entityClassMap.put(
                type.replaceAll("([a-z])([A-Z]+)", "$1_$2").toLowerCase(),
                rawType);
        this.moduleMap.put(type, info.getModule());
        this.entityInfoMap.put(type, info);
        this.serviceMap.put(type, service);
        this.class2typeMap.put(rawType, type);
        this.class2moduleMap.put(rawType, info.getModule());
        this.class2entityInfoMap.put(rawType, info);
        this.class2serviceMap.put(rawType, service);
    }

    /**
     * 获取实例信息列表<br/>
     * <功能详细描述>
     *
     * @return [参数说明]
     * @return List<BasicDataEntityInfo> [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public List<BasicDataEntityInfo> getEntityInfoList() {
        List<BasicDataEntityInfo> infoList = new ArrayList<>();

        for (BasicDataEntityInfo info : this.entityInfoMap.values()) {
            infoList.add(info);
        }
        return infoList;
    }

    /**
     * 获取实例信息列表<br/>
     * <功能详细描述>
     *
     * @return [参数说明]
     * @return List<BasicDataEntityInfo> [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public List<BasicDataEntityInfo> getEntityInfoList(String module,
                                                       List<BasicDataViewTypeEnum> viewTypes) {
        List<BasicDataEntityInfo> infoList = new ArrayList<>(
                this.entityInfoMap.values());

        if (!StringUtils.isEmpty(module)) {
            CollectionUtils.filter(infoList,
                    (BasicDataEntityInfo object) -> module
                            .equals(object.getModule()));
        }
        if (!CollectionUtils.isEmpty(viewTypes)) {
            CollectionUtils.filter(infoList,
                    (BasicDataEntityInfo object) -> viewTypes
                            .contains(object.getViewType()));
        }

        return infoList;
    }

    /**
     * 根据类型名称获取对应的类实例<br/>
     * <功能详细描述>
     *
     * @param type
     * @return [参数说明]
     * @return Class<? extends BasicData> [返回类型说明]
     * @throws throws [异常类型] [异常说明]
     * @see [类、类#方法、类#成员]
     */
    public Class<? extends BasicData> getEntityClass(String type) {
        AssertUtils.notEmpty(type, "type is empty.");

        if (this.entityClassMap.containsKey(type)) {
            return this.entityClassMap
                    .get(type);
        } else if (this.entityClassMap.containsKey(type.toLowerCase())) {
            return this.entityClassMap
                    .get(type.toLowerCase());
        }

        return null;
    }

    /**
     * 获取类对应的类型名
     * 该方法用于根据传入的实体类获取其对应的类型名。
     *
     * @param entityClass 需要获取类型名的实体类的Class对象，不能为空。
     * @return 返回该实体类对应的类型名，如果实体类没有对应的类型名则返回null。
     */
    public String getType(Class<? extends BasicData> entityClass) {
        // 确保传入的实体类Class对象不为空
        AssertUtils.notNull(entityClass, "entityClass is null.");

        // 从class2typeMap中获取并返回实体类对应的类型名
        return this.class2typeMap.get(entityClass);
    }

    /**
     * 获取指定类型的实例信息
     * <功能详细描述>：根据提供的类型参数，从实体信息映射中检索对应的实体信息对象。
     *
     * @param type 指定实体的类型，用于查找对应的实体信息
     * @return BasicDataEntityInfo 返回查找到的实体信息对象，如果没有找到则返回null
     */
    public BasicDataEntityInfo getEntityInfo(String type) {
        // 确保类型参数不为空
        AssertUtils.notEmpty(type, "type is empty.");

        // 从实体信息映射中获取指定类型的实体信息
        return this.entityInfoMap.get(type);
    }


    /**
     * 获取指定实体类的实例信息
     * <p>此方法用于根据提供的实体类Class对象，从内部映射中检索该实体类的实例信息。实体类必须继承自BasicData。</p>
     *
     * @param entityClass 需要获取实例信息的实体类的Class对象。不可为null。
     * @return 返回对应实体类的实例信息，类型为BasicDataEntityInfo。如果实体类未找到，则返回null。
     */
    public BasicDataEntityInfo getEntityInfo(
            Class<? extends BasicData> entityClass) {
        // 确保传入的实体类Class对象不为null
        AssertUtils.notNull(entityClass, "entityClass is null.");

        // 从类到实体信息的映射中获取指定实体类的实例信息
        return this.class2entityInfoMap.get(entityClass);
    }


    /**
     * 获取指定类型的模块信息
     * <功能详细描述>：根据提供的类型参数，从模块映射中检索对应的模块信息。
     *
     * @param type 模块的类型，用于查找对应的模块信息。不能为空。
     * @return BasicDataEntityInfo 返回查找到的模块信息。如果未找到对应类型，则返回null。
     */
    public String getModule(String type) {
        // 确保type参数不为空
        AssertUtils.notEmpty(type, "type is empty.");

        // 从模块映射中获取指定类型的模块信息
        return this.moduleMap.get(type);
    }


    /**
     * 获取指定实体类对应的模块信息
     * <p>此方法通过实体类的Class对象来查询其对应的模块信息。要求传入的实体类必须是BasicData的子类。</p>
     *
     * @param entityClass 需要查询模块信息的实体类的Class对象，不能为空
     * @return 返回该实体类所对应的模块信息，如果不存在映射关系，则返回null
     */
    public String getModule(Class<? extends BasicData> entityClass) {
        // 确保传入的实体类Class对象不为空
        AssertUtils.notNull(entityClass, "entityClass is null.");

        // 通过class2moduleMap映射关系，获取对应的模块信息
        return this.class2moduleMap.get(entityClass);
    }


    /**
     * 获取指定类型的实例信息
     * <功能详细描述>：根据提供的类型参数，从服务映射中检索并返回相应的BasicDataService实例。
     *
     * @param type 指定实例的类型，不能为空字符串。
     * @return 返回对应类型的BasicDataService实例，泛型参数继承自BasicData。
     */
    public BasicDataService<? extends BasicData> getService(String type) {
        // 确保类型参数不为空
        AssertUtils.notEmpty(type, "type is empty.");

        // 从服务映射中获取并返回对应的实例
        return this.serviceMap.get(type);
    }


    /**
     * 获取对应实体类的 service 实例信息
     * 该方法用于根据指定的实体类获取其对应的BasicDataService实例，用于对实体进行操作。
     *
     * @param entityClass 需要获取服务的实体类的Class对象，不能为空。
     * @return 返回针对指定实体类的BasicDataService实例，允许返回null。
     */
    public BasicDataService<? extends BasicData> getService(
            Class<? extends BasicData> entityClass) {
        // 确保传入的实体类不为空
        AssertUtils.notNull(entityClass, "entityClass is null.");

        // 从类到服务的映射中获取对应实体类的服务实例
        return this.class2serviceMap.get(entityClass);
    }


}